package controller;

import CPU.CPU;
import action.createprocess;
import device.Device;
import device.DeviceDispatcher;
import memory.Memory;
import memory.MemoryDispatcher;
import process.PCB;
import process.ProcessDispatcher;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Path;
import javafx.stage.Stage;

import java.net.URL;
import java.text.DecimalFormat;
import java.util.ResourceBundle;

public class ScheduiUIController implements Initializable{

    private CPU cpu;
    private MemoryDispatcher memoryDispatcher;
    private ProcessDispatcher processDispatcher;
    private DeviceDispatcher deviceDispatcher;
    private  FXMLLoader fxmlLoader;
    public static ScheduiUIController scheduiUIController;

    @FXML // fx:id="BlockedRRT"
    private TableColumn<PCB, DoubleProperty> BlockedRRT; // Value injected by FXMLLoader

    @FXML // fx:id="endedRT"
    private TableColumn<PCB, DoubleProperty> endedRT; // Value injected by FXMLLoader

    @FXML // fx:id="BlockedTRT"
    private TableColumn<PCB, DoubleProperty> BlockedTRT; // Value injected by FXMLLoader

    @FXML // fx:id="src.CPU"
    private ImageView CPU1; // Value injected by FXMLLoader

    @FXML // fx:id="endedName"
    private TableColumn<PCB, StringProperty> endedName; // Value injected by FXMLLoader

    @FXML // fx:id="DevicePName"
    private TableColumn<Device, StringProperty> DevicePName; // Value injected by FXMLLoader

    @FXML // fx:id="processBar"
    private TableColumn<PCB, Double> processBar; // Value injected by FXMLLoader

    @FXML // fx:id="DeviceRT"
    private TableColumn<Device, IntegerProperty> DeviceRT; // Value injected by FXMLLoader

    @FXML // fx:id="endedresult"
    private TableColumn<PCB, StringProperty> endedresult; // Value injected by FXMLLoader

    @FXML // fx:id="RemanTime"
    private TextField RemanTime; // Value injected by FXMLLoader

    @FXML // fx:id="RunningOrder"
    private TextField RunningOrder; // Value injected by FXMLLoader

    @FXML // fx:id="BlockedDeviceType"
    private TableColumn<PCB, Character> BlockedDeviceType; // Value injected by FXMLLoader

    @FXML // fx:id="Readylength"
    private TableColumn<PCB, IntegerProperty> Readylength; // Value injected by FXMLLoader

    @FXML // fx:id="ReadyRestTime"
    private TableColumn<PCB, DoubleProperty> ReadyRestTime; // Value injected by FXMLLoader

    @FXML // fx:id="BlockedProcess"
    private TableView<PCB> BlockedProcess; // Value injected by FXMLLoader

    @FXML // fx:id="ReadyRT"
    private TableColumn<PCB, DoubleProperty> ReadyRT; // Value injected by FXMLLoader

    @FXML // fx:id="BlockedName"
    private TableColumn<PCB, StringProperty> BlockedName; // Value injected by FXMLLoader

    @FXML // fx:id="ProcessUsage"

    private TextField ProcessUsage; // Value injected by FXMLLoader

    @FXML // fx:id="playBTN"
    private Button playBTN; // Value injected by FXMLLoader

    @FXML // fx:id="EndedTable"
    private TableView<PCB> EndedTable; // Value injected by FXMLLoader

    @FXML // fx:id="TemporaryResults"
    private TextField TemporaryResults; // Value injected by FXMLLoader

    @FXML // fx:id="RunnningProcess"
    private TextField RunnningProcess; // Value injected by FXMLLoader

    @FXML // fx:id="createBTN"
    private Button createBTN; // Value injected by FXMLLoader

    @FXML // fx:id="stackPane"
    private StackPane stackPane; // Value injected by FXMLLoader

    @FXML // fx:id="MemoryUsage"
    private TextField MemoryUsage; // Value injected by FXMLLoader

    @FXML // fx:id="DeviceUsage"
    private TextField DeviceUsage; // Value injected by FXMLLoader

    @FXML // fx:id="Ready"
    private TableView<PCB> Ready; // Value injected by FXMLLoader

    @FXML // fx:id="Readyname"
    private TableColumn<PCB, StringProperty> Readyname; // Value injected by FXMLLoader

    @FXML // fx:id="BlockeddeviceTime"
    private TableColumn<PCB, IntegerProperty> BlockeddeviceTime; // Value injected by FXMLLoader

    @FXML // fx:id="integrateBTN"
    private Button integrateBTN; // Value injected by FXMLLoader

    @FXML // fx:id="DeviceTable"
    private TableView<Device> DeviceTable; // Value injected by FXMLLoader

    @FXML // fx:id="src.device"
    private TableColumn<Device, Character> devicename; // Value injected by FXMLLoader

    @FXML
    private BorderPane borderPane;
//    @FXML
//    public Pane memorypane;
    @FXML
    private Path pathrunToEnd;


    @FXML
    public Path pathrunToblock;

    @FXML
    private Path pathreadyToRun;
    @FXML
    private Path pathrunToReady;
    @FXML
    private Path pathblockTodevice;
    @FXML
    private VBox OSbox;
    @FXML
    private Pane panerunToEnd;
    @FXML
    public Pane panerunToblock;
    @FXML
    private Pane panereadyToRun;
    @FXML
    private Pane panerunToReady;
    @FXML
    private Pane paneblockTodevice;
    @FXML
    private TextField Runnningtime;
//    @FXML
//    public TableColumn<ProcessHistory, DoubleProperty> Time;
//    @FXML
//    public TableColumn<ProcessHistory, StringProperty> Process;
//    @FXML
//    public TableColumn<ProcessHistory, StringProperty> Status;
//    @FXML
//    public TableColumn<ProcessHistory, StringProperty> Operation;
//    @FXML
//    public TableColumn<ProcessHistory, StringProperty> Result;
//    @FXML
//    public TableView<ProcessHistory> ProcessHistoryTable;

    private ObservableList<Pane> panes;

    private Stage HistoryStage=new Stage();

    private Stage UsageStage=new Stage();

    @Override
    public void initialize(URL location, ResourceBundle resources) {
//        初始化cpu
        this.cpu= CPU.getInstance();
//     初始化内存分配器
        this.memoryDispatcher= MemoryDispatcher.getInstance();
//     初始化进程调度器
        this.processDispatcher= ProcessDispatcher.getInstance();
//     设备调度器
        this.deviceDispatcher= DeviceDispatcher.getInstance();
        this.processDispatcher.setBlockedTableView(this.BlockedProcess,this.BlockedName,this.BlockedDeviceType,this.BlockeddeviceTime,this.BlockedTRT,this.BlockedRRT);
        this.processDispatcher.setDeviceTableView(this.DeviceTable,this.devicename,this.DevicePName,this.DeviceRT);
        this.processDispatcher.setEndTableView(this.EndedTable,this.endedRT,this.endedName,this.endedresult);

        this.processDispatcher.setReadyTableView(this.Ready,this.Readyname,this.ReadyRT,this.ReadyRestTime,this.Readylength,this.processBar);

        //this.processDispatcher.setHistoryTableView(ProcessHistoryTable,Result,Operation,Status,Process,Time);

        ProcessDispatcher.setPaneblockTodevice(this.paneblockTodevice);
        ProcessDispatcher.setPanedeviceToReady(this.panerunToReady);
        ProcessDispatcher.setPanereadyToRun(this.panereadyToRun);
        ProcessDispatcher.setPanerunToEnd(this.panerunToEnd);
        ProcessDispatcher.setPanerunToblock(this.panerunToblock);

        this.processDispatcher.setPathblockTodevice(this.pathblockTodevice);
        this.processDispatcher.setPathrunToReady(this.pathrunToReady);
        this.processDispatcher.setPathreadyToRun(this.pathreadyToRun);
        this.processDispatcher.setPathRunToBlock(this.pathrunToblock);
//        this.processDispatcher.setPathrunToEnd(this.pathrunToEnd);
//
//        this.OSbox.prefWidthProperty().bind(memorypane.widthProperty().multiply((double)50/512));
//        this.OSbox.prefHeightProperty().bind(memorypane.heightProperty());

        CPU.UI_CONTROLLER=this;
        ProcessDispatcher.scheduiUIController=this;
//        MemoryDispatcher.memoryPane=memorypane;
//     计时
        ProcessDispatcher.timekeeping();
        updateRunTime();
    }



    @FXML
    private void playorstop(ActionEvent event) {
        if(ProcessDispatcher.isrunning){
            ProcessDispatcher.stop();
            playBTN.setText("开始运行");
        }else{
            ProcessDispatcher.play();
            playBTN.setText("暂停运行");
        }
        return;
    }

    @FXML
    private void createprocess(ActionEvent event) {
//        创建进程
        new createprocess();
        return;
    }

    public  void showHistory(ActionEvent event){
        //打开展示进程运行历史记录
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(getClass().getResource("/view/ProcessHistory.fxml"));
            Parent root = (Parent) loader.load();
            Scene scene = new Scene(root);
            HistoryStage.setScene(scene);
            HistoryStage.setTitle("运行记录");
            // Main.stage.setResizable(false);
            HistoryStage.show();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return;
    }

    public void showUsage(ActionEvent event){
        //展示占用情况，各个进程分别占用情况,实时更新
        ObservableList<PieChart.Data> answer = FXCollections.observableArrayList();
        DecimalFormat df  =new  DecimalFormat("#.00");
        int size=50;//初始系统占用
        answer.addAll(new PieChart.Data("系统占用"+ df.format(50*100 / 512) +"%", 50));
        for (PCB pcb: Memory.PCBlist){
            size+=pcb.getLength();
            answer.addAll(new PieChart.Data(pcb.getName()+" 占用"+ df.format(pcb.getLength()*100 / 512) +"%", pcb.getLength()));
        }
        answer.addAll(new PieChart.Data("未被占用"+ df.format((512-size)*100 / 512) +"%", 512-size));
        PieChart pieChart = new PieChart();
        pieChart.setData(answer);
        UsageStage.setTitle("内存分布");
        StackPane root = new StackPane();
        root.getChildren().add(pieChart);
        UsageStage.setScene(new Scene(root,800,500));
        UsageStage.show();
    }

    public void updateUsage(){
        ObservableList<PieChart.Data> answer = FXCollections.observableArrayList();
        DecimalFormat df  =new  DecimalFormat("#.00");
        int size=50;//初始系统占用
        answer.addAll(new PieChart.Data("系统占用"+ df.format(50*100 / 512) +"%", 50));
        for (PCB pcb:Memory.PCBlist){
            size+=pcb.getLength();
            answer.addAll(new PieChart.Data(pcb.getName()+" 占用"+ df.format(pcb.getLength()*100 / 512) +"%", pcb.getLength()));
        }
        answer.addAll(new PieChart.Data("未被占用"+ df.format((512-size)*100 / 512) +"%", 512-size));
        PieChart pieChart = new PieChart();
        pieChart.setData(answer);
        UsageStage.setTitle("内存分布");
        StackPane root = new StackPane();
        root.getChildren().add(pieChart);
        UsageStage.setScene(new Scene(root,800,500));
    }

    @FXML
    private void integrateMemory(ActionEvent event) {
        MemoryDispatcher.mergeFragments();
        return;

    }

    private void updateRunTime(){
        Thread thread=new Thread(){
            public void run(){
                while (true){
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            Runnningtime.setText(String.valueOf(ProcessDispatcher.getRunningtime()/1000.0D));
                        }
                    });
                    try {
                        Thread.sleep(1L);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.setDaemon(true);
        thread.start();
    }
    public TextField getRemanTime() {
        return RemanTime;
    }

    public TextField getRunningOrder() {
        return RunningOrder;
    }


    public TextField getProcessUsage() {
        return ProcessUsage;
    }


    public TextField getTemporaryResults() {
        return TemporaryResults;
    }

    public TextField getRunnningProcess() {
        return RunnningProcess;
    }


    public TextField getMemoryUsage() {
        return MemoryUsage;
    }


    public TextField getDeviceUsage() {
        return DeviceUsage;
    }
}
